#include <iostream>
#include <vector>
//#include <ctime>

using namespace std;


const int	maxN = 20 + 1;
const int	maxM = 30 + 1;
const int	maxNM = maxN * maxM + 10;
const int	INF = 1 << 29;

struct edge_t
{
	int end_point;
	int cap;
	int next;
	edge_t(int e, int c, int n) : end_point(e), cap(c), next(n) {}
};

int		attack_c[maxNM], reach[maxNM][maxNM], pre_node[maxNM], pre_edge[maxNM], queue[maxNM], disable[maxNM], score[maxNM], m_clock[maxNM][maxN], dist[maxNM], used[maxNM];
int		edge_list[maxNM];
//clock_t		start_time;
vector<edge_t>	edges;
vector<int>	reach_list[maxNM];

int		N, M;

void	add_edge(int u, int v, int c)
{
	edges.push_back(edge_t(v, c, edge_list[u])); edge_list[u] = edges.size() - 1;
	edges.push_back(edge_t(u, 0, edge_list[v])); edge_list[v] = edges.size() - 1;
}

void	get_input()
{
	scanf("%d%d", &N, &M);

	memset(reach, 0, sizeof(reach));
	for (int i = 0; i < N * M; ++i) reach_list[i].clear();

	for (int i = 0; i < N * M; ++i)
	{
		scanf("%d%d", &score[i], &attack_c[i]);

		for (int j = 0; j < attack_c[i]; ++j)
		{
			int p, q;
			scanf("%d%d", &p, &q);
			reach_list[p * M + q].push_back(i);
			reach[p * M + q][i] = 1;
		}
	}
}

bool	markLevel(int s, int t) 
{
	int head, tail;

	memset(dist , 0xff , sizeof(dist));
	dist[t] = 0;
	queue[head = tail = 0] = t;

	int	u;
	while (head <= tail) {
		u = queue[head ++];
		used[u] = edge_list[u];
		for (int i = edge_list[u]; i >= 0; i = edges[i].next)
			if (edges[i ^ 1].cap > 0) {
				int v = edges[i].end_point;
				if (dist[v] < 0) {
					dist[v] = dist[u] + 1;
					queue[ ++ tail ] = v;
				}
			}
	}
	return	dist[s] >= 0;
}

int	extendPath(int s, int t, int u , int delta) 
{
	if (u == t) return delta;
	for (int& i = used[u]; i >= 0; i = edges[i].next) 
	{
		if (edges[i].cap > 0 && dist[ edges[i].end_point ] + 1 == dist[u]) 
		{
			int	d = extendPath(s, t, edges[i].end_point , min(delta , edges[i].cap) );
			if (d > 0) 
			{
				edges[i].cap -= d; edges[ i ^ 1 ].cap += d;
				return	d;
			}
		}
	}
	return 0;
}

int	max_flow(int s, int t)
{
	int	ret = 0;
	int	delta;
	while ( markLevel(s, t) ) {
		while ( (delta = extendPath(s, t, s , INF)) > 0 )
			ret += delta;
	}
	return	ret;
}

void	DFS(int i)
{
	disable[i] = 2;
	m_clock[i][i / M] = i % M;

	for (int j = 0; j < N * M; ++j) if (reach[i][j])
	{
		if (disable[j] < 0)
			DFS(j);

		if (disable[j] == 2 || disable[j] == 1)
		{
			disable[i] = 1;
			return;
		}

		for (int k = 0; k < N; ++k)
			if (m_clock[j][k] < m_clock[i][k])
				m_clock[i][k] = m_clock[j][k];
	}

	disable[i] = 0;
}

void	solve()
{
	//	build_graph
	memset(disable, 255, sizeof(disable));

	for (int i = 0; i < N * M; ++i) for (int k = 0; k < N; ++k) m_clock[i][k] = M;

	for (int i = 0; i < N * M; i += M)
		for (int j = 0; j < M - 1; ++j)
		{
			reach[i + j][i + j + 1] = 1;
			reach_list[i + j].push_back(i + j + 1);
		}

	for (int i = 0; i < N * M; ++i)
		if (disable[i] < 0) DFS(i);

	//cout << clock() - start_time << endl;
	//for (int i = 0; i < N * M; ++i)
	//	for (int k = 0; k < N; ++k)
	//		for (int j = m_clock[i][k]; j < M; ++j)
	//			reach[i][k * M + j] = 1;

	//for (int k = 0; k < N * M; ++k)
	//for (int i = 0; i < N * M; ++i)
	//for (int j = 0; j < N * M; ++j) 
	//	if (reach[i][k] && reach[k][j]) reach[i][j] = 1;

	//for (int i = 0; i < N * M; ++i)
	//	for (int j = 0; j < N * M; ++j) if (i != j && reach[i][j] && reach[j][i])
	//		disable[i] = disable[j] = 1;

	//for (int i = 0; i < N * M; ++i)
	//	for (int j = 0; j < N * M; ++j) if (reach[i][j] && disable[j])
	//		disable[i] = 1;

	//for (int i = 0; i < N * M; ++i)
	//	if (disable[i]) cout << i << ' '; cout << endl;

#if 0
	int s = N * M, t = s + 1;
	int total_posi_score = 0;

	edges.clear();
	memset(edge_list, 255, sizeof(edge_list));
	for (int i = 0; i < N * M; ++i) if (!disable[i])
	{
		for (int j = 0; j < reach_list[i].size(); ++j)
		{
			int v = reach_list[i][j];
			if (!disable[v])
				add_edge(i, v, INF);
		}
		if (score[i] > 0)
		{
			total_posi_score += score[i];
			add_edge(s, i, score[i]);
		} else
		if (score[i] < 0)
			add_edge(i, t, -score[i]);
	}
#else
	vector<int> x, y;
	for (int i = 0; i < N * M; ++i) if (!disable[i])
	{
		if (score[i] > 0) x.push_back(i);
		if (score[i] < 0) y.push_back(i);
	}

	int s = x.size() + y.size(), t = s + 1;
	edges.clear();
	memset(edge_list, 255, sizeof(edge_list));

	for (int i = 0; i < x.size(); ++i)
		for (int j = 0; j < y.size(); ++j)
			if (reach[x[i]][y[j]] || m_clock[x[i]][y[j] / M] <= y[j] % M)
				add_edge(i, j + x.size(), INF);

	int total_posi_score = 0;

	for (int i = 0; i < x.size(); ++i) total_posi_score += score[x[i]];
	for (int i = 0; i < x.size(); ++i) add_edge(s, i, score[x[i]]);
	for (int j = 0; j < y.size(); ++j) add_edge(j + x.size(), t, -score[y[j]]);
#endif

	int max_profit = total_posi_score - max_flow(s, t);
	//cout << clock() - start_time << endl;

	cout << max_profit << endl;
}

int	main()
{
	//freopen("zombie.in", "r", stdin);
	//freopen("zombie.out", "w", stdout);
	//start_time = clock();
	get_input();
	//cout << clock() - start_time << endl;
	//start_time = clock();
	solve();
	return 0;
}
